#include "global.h"
#include "extEEPROM.h"


#define DATAOUT 11//MOSI
#define DATAIN  12//MISO 
#define SPICLOCK  13//sck
int slaveSelectPin = 10;

//opcodes
#define WREN  6
#define WRDI  4
#define RDSR  5
#define WRSR  1
#define READ  3
#define WRITE 2

const int cellLen = sizeof(long);

void extEEPROM::init(){
	SPI.begin();
	SPI.setBitOrder(MSBFIRST);
	SPI.setClockDivider(SPI_CLOCK_DIV4);
	SPI.setDataMode(SPI_MODE0);
	SPI.detachInterrupt();
	delay(10);
	digitalWrite(slaveSelectPin, LOW);
	SPI.transfer(WREN);
	digitalWrite(slaveSelectPin, HIGH);
	delay(10);
}


uint8_t extEEPROM::readStatus(){
	volatile uint8_t data;

	digitalWrite(slaveSelectPin, LOW);
	SPI.transfer(RDSR); //transmit read opcode
	data = SPI.transfer(0xFF); //get data byte
	digitalWrite(slaveSelectPin, HIGH);
	delay(10);
	return data;
}




uint8_t extEEPROM::readByte(unsigned long EEPROM_address)
{
  //READ EEPROM
  int data;
  digitalWrite(slaveSelectPin, LOW);
  SPI.transfer(READ); //transmit read opcode
  SPI.transfer((byte)(EEPROM_address>>8));   //send MSByte address first
  SPI.transfer((byte)(EEPROM_address));      //send LSByte address
  data = SPI.transfer(0xFF); //get data byte
  //add code to check status of chip before going on to more reads
  digitalWrite(slaveSelectPin, HIGH); //release chip, signal end transfer
  return data;
}


void extEEPROM::writeByte(unsigned long address, const uint8_t value){
	digitalWrite(slaveSelectPin,LOW);
	SPI.transfer(WREN);
  	digitalWrite(slaveSelectPin, HIGH);
	delay(10);

	digitalWrite(slaveSelectPin,LOW);
	SPI.transfer(WRITE); //write instruction
	SPI.transfer((byte)(address>>8));   //send MSByte address first
	SPI.transfer((byte)(address));      //send LSByte address
	SPI.transfer(value); //write data byte

	//block write protection level?  
	//add code to check status of chip before going on to more writes
	digitalWrite(slaveSelectPin, HIGH);
	delay(10);

	digitalWrite(slaveSelectPin,LOW);
	SPI.transfer(WRDI);
	digitalWrite(slaveSelectPin, HIGH);
}


void extEEPROM::writeCoordPack(volatile uint16_t address, Coordinate Coords2Store[]){
	volatile uint8_t outBuff[COORD_STORE_LEN*10+8];
	outBuff[127] = 0xfe;
	outBuff[126] = 0xfd;
	outBuff[125] = 0xfc;
	outBuff[124] = 0xfb;
	outBuff[123] = 0xfa;
	outBuff[122] = 0xf9;
	outBuff[121] = 0xf8;
	outBuff[120] = 0xf7;

	int i,c;
	uint8_t status;
	for(c=0; c<10; c++){  //C++ ! get it?
	uint8_t* ptrCoord = (uint8_t*)(&Coords2Store[c].lat);
		for(i=0; i<COORD_STORE_LEN; i++){
			if(i==4) 
				ptrCoord = (uint8_t*)(&Coords2Store[c].lon);
			else if(i==8) 
				ptrCoord = (uint8_t*)(&Coords2Store[c].timeStamp);

			outBuff[i+c*COORD_STORE_LEN]=*ptrCoord++;
		}
	}

	
#ifdef WR_VERBOSE
	Serial.print("ADR: ");
	Serial.print((uint8_t)(address>>8));
	Serial.println((uint8_t)address);
	for(int p=0; p<10; p++){
		for(i=0; i<COORD_STORE_LEN; i++){
			Serial.print(outBuff[p*COORD_STORE_LEN+i]); //write data byte
			Serial.print(", ");
		}
		Serial.println();
	}
#endif



	digitalWrite(slaveSelectPin,LOW);
	SPI.transfer(WRITE); //write instruction
	SPI.transfer((uint8_t)(address>>8));   //send MSByte address first
	SPI.transfer((uint8_t)address);      //send LSByte address

	for(i=0; i<128; i++){
		SPI.transfer(outBuff[i]); //write data byte
	}
	digitalWrite(slaveSelectPin, HIGH);
	//while(status&0x01==1)
	//{
	//	status = readStatus();
	//	Serial.println(status);
	//	delay(100);
	//}
	//Serial.println();
}


		
Coordinate extEEPROM::readCoord(volatile uint16_t address){
	int i;
	uint8_t status;
	volatile uint8_t inBuff[COORD_STORE_LEN];
	Coordinate returnCoord;

	digitalWrite(slaveSelectPin, LOW);
	SPI.transfer(READ); //transmit read opcode

	SPI.transfer((uint8_t)(address>>8));   //send MSByte address first
	SPI.transfer((uint8_t)address);      //send LSByte address

	for(i=0; i<COORD_STORE_LEN; i++){
		inBuff[i] = SPI.transfer(0xff); //write data byte
	}
	digitalWrite(slaveSelectPin,HIGH); //release chip

#ifdef RD_VERBOSE
	Serial.print("ADR: ");
	Serial.print((uint8_t)(address>>8));
	Serial.println((uint8_t)address);
	
	for(i=0; i<COORD_STORE_LEN; i++){
		Serial.print(inBuff[i]); //write data byte
		Serial.print(", ");
	}
	Serial.println();
#endif


	returnCoord.lat = *(long*)&inBuff[0];
	returnCoord.lon = *(long*)&inBuff[4];
	returnCoord.timeStamp = *(unsigned long*)&inBuff[8];
	

	return returnCoord;
}

extEEPROM spiPROM;